package com.xiaojie.sharding.sphere.shardingalgorithm;

import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collection;

/**
 * @Description:自定义数据库分片算法 数据库的分片字段可以和分表分片字段一样，也可以不一样
 * 下面配置 分库字段按照age字段，如果年龄超过30那么放在ds0,如果没有超过放在ds1,
 * 分表字段按照id字段存放。偶数存放到tb_user_0、奇数存放到tb_user_1
 * @author: yan
 * @date: 2022.03.12
 */
@Component
public class MyDBShardingAlgorithm implements PreciseShardingAlgorithm<Integer>, RangeShardingAlgorithm<Long> {

    @Override
    public String doSharding(Collection<String> dbNames, PreciseShardingValue<Integer> shardingValue) {
//        for (String dbName : dbNames) {
//            /**
//             * 取模算法，分片健 % 表数量 数据库
//             */
//            Integer age = shardingValue.getValue();
//            String tableIndex = age%dbNames.size()+"";
//            if (dbName.endsWith(tableIndex)) {
//                return dbName;//返回数据库名称 比如db0,db1
//            }
//        }
        //如果大于30岁放在db0,小于等于30放在db1
        if (shardingValue.getValue() > 30) {
            return (String) dbNames.toArray()[0];
        } else {
            return (String) dbNames.toArray()[1];
        }
//        throw new IllegalArgumentException();
    }

    @Override
    public Collection<String> doSharding(Collection<String> dbNames, RangeShardingValue<Long> shardingValue) {
        Collection<String> collect = new ArrayList<>();//数据库节点名称
        Range valueRange = shardingValue.getValueRange();//查询返回
        String lowerPoint = String.valueOf(valueRange.hasLowerBound() ? valueRange.lowerEndpoint() : "");//下限
        String upperPoint = String.valueOf(valueRange.hasUpperBound() ? valueRange.upperEndpoint() : "");//上限
        //判断上限，下限值是否存在，如果不存在赋给默认值。用于处理查询条件中只有 >或<一个条件，不是一个范围查询的情况
        long lowerEndpoint = 0; //最小值
        long lupperEndpoint = 0;//最大值
        if (!lowerPoint.isEmpty() && !upperPoint.isEmpty()) {
            lowerEndpoint = Math.abs(Long.parseLong(lowerPoint));
            lupperEndpoint = Math.abs(Long.parseLong(upperPoint));
        } else if (lowerPoint.isEmpty() && !upperPoint.isEmpty()) {
            lupperEndpoint = Math.abs(Long.parseLong(upperPoint));
            lowerEndpoint = 0;
        } else if (!lowerPoint.isEmpty() && upperPoint.isEmpty()) {
            lowerEndpoint = Math.abs(Long.parseLong(lowerPoint));
            lupperEndpoint = 40;
        }
        // 循环范围计算分库逻辑
        for (long i = lowerEndpoint; i <= lupperEndpoint; i++) {
            for (String db : dbNames) {
                if (db.endsWith(i % dbNames.size() + "")) {
                    collect.add(db);
                }
            }
        }
        return collect;
    }
}
